﻿using Newtonsoft.Json;
using NPOI.POIFS.Crypt.Dsig;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace YB_Server_Windows
{
    public class SseClient
    {
        [Serializable]
        public class WmsSseMessage
        {
            public string Kind { get; set; }
            public string Title { get; set; }
            public string Content { get; set; }
            public string SendUname { get; set; }
            public string SendTime { get; set; }
        }
        [Serializable]
        public class SseMessage
        {
            public string Id { get; set; }
            public string Event { get; set; }
            public string Data { get; set; }
            override public string ToString()
            {
                string outdata = JsonConvert.SerializeObject(this);
                return outdata;
            }
        }

        private readonly HttpClient _httpClient;
        private readonly string _url;
        private readonly string _token;
        private CancellationTokenSource _cancellationTokenSource;

        public event Action OnOpen;
        public event Action<SseMessage> OnMessage;
        public event Action OnError;
        public event Action OnClose;

        public SseClient(string url, string token)
        {
            _httpClient = new HttpClient();
            _url = url;
            _token = token;
            _cancellationTokenSource = new CancellationTokenSource();
        }
        public T DeepCopy<T>(T other)
        {
            if (other == null)
                return default(T);

            BinaryFormatter formatter = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream())
            {
                formatter.Serialize(ms, other);
                ms.Position = 0;
                return (T)formatter.Deserialize(ms);
            }
        }

        public void Start()
        {
            Task.Run(async () =>
        {
            _httpClient.DefaultRequestHeaders.Add("Accept", "text/event-stream");
            _httpClient.DefaultRequestHeaders.Add("Authorization", _token);
            _httpClient.DefaultRequestHeaders.Add("appid", "9");
            _httpClient.DefaultRequestHeaders.Add("Kind", "PrintPlug");
            while (!_cancellationTokenSource.Token.IsCancellationRequested)
            {
                try
                {
                    using (var response = await _httpClient.GetAsync(_url, HttpCompletionOption.ResponseHeadersRead, _cancellationTokenSource.Token))
                    {
                        response.EnsureSuccessStatusCode();

                        using (var reader = new StreamReader(await response.Content.ReadAsStreamAsync()))
                        {
                            OnOpen?.Invoke();
                            SseMessage message = new SseMessage();
                            while (!_cancellationTokenSource.Token.IsCancellationRequested && !reader.EndOfStream)
                            {
                                string line = await reader.ReadLineAsync();
                                if (line.StartsWith("id:"))
                                {
                                    message.Id = line.Substring(4).Trim();
                                }
                                if (line.StartsWith("event:"))
                                {
                                    message.Event = line.Substring(6).Trim();
                                }
                                if (line.StartsWith("data:"))
                                {
                                    message.Data = line.Substring(5).Trim();
                                }
                                if (line.Length == 0)
                                {
                                    OnMessage?.Invoke(DeepCopy(message));
                                }
                            }
                        }
                    }
                }

                catch (OperationCanceledException e)
                {
                    // Log or handle cancellation
                    YB.Log.Write("链接SSE错误" + e.Message);
                }
                catch (Exception ex)
                {
                    OnError?.Invoke();
                    YB.Log.Write("链接SSE错误: " + ex.Message);
                }
                finally
                {
                    OnClose?.Invoke();
                }
                Thread.Sleep(1000);
            }
        });
        }

        public void Stop()
        {
            _cancellationTokenSource.Cancel();
        }
    }
}
